#include <string>
#include <vector>
#include <cstdint>
#include <iostream>
#include <cstring>
#include <cassert>

// 缓冲区设计
#define BUFFER_SIZE 1024
#define MAX_CAPACITY 1048576

class Buffer
{
private:
    std::vector<char> _buffer; // 缓冲区
    size_t _write_pos; // 写偏移
    size_t _read_pos;  // 读偏移
    size_t _capacity;  // 总容量

public:
    // 构造函数
    Buffer() : _buffer(BUFFER_SIZE, 0), _write_pos(0), _read_pos(0), _capacity(BUFFER_SIZE) {}
    Buffer(const Buffer& Buf) : _buffer(Buf._buffer), _write_pos(Buf._write_pos), _read_pos(Buf._read_pos), _capacity(Buf._capacity) {}
    // 赋值运算符重载
    Buffer& operator=(Buffer Buf) {
        std::swap(_buffer, Buf._buffer);
        std::swap(_write_pos, Buf._write_pos);
        std::swap(_read_pos, Buf._read_pos);
        std::swap(_capacity, Buf._capacity);
        return *this;
    }

public:
    // 单项功能设计

    // 调整缓冲区大小
    void Resize(uint32_t size){
        _buffer.resize(size);
        _capacity = size;
        if (_write_pos > _capacity) _write_pos = _capacity;
    }

    // 获取缓冲区首部地址
    char* Begin(){
        return &_buffer[0];
    }

    // 获取读地址
    char* ReadAddress(){
        return &_buffer[_read_pos];
    }

    // 获取写地址
    char* WriteAddress(){
        return &_buffer[_write_pos];
    }

    // 获取当前缓冲区中的数据长度
    size_t DataLength(){
        return _write_pos - _read_pos;
    }

    // 更新读偏移
    void ModifyReadOffset(size_t len){
        _read_pos += len;
    }

    // 更新写偏移
    void ModifyWriteOffset(size_t len){
        _write_pos += len;
    }

    // 获取头部剩余空间
    size_t HeadRemainSpace(){
        return _read_pos;
    }

    // 获取尾部剩余空间
    size_t TailRemainSpace(){
        return _capacity - _write_pos;
    }

    // 判断尾部剩余空间是否足够写入定长数据：足够写入则直接返回
    // 不够写入则再做判断：1、头部剩余空间+尾部剩余空间是够足够写入，足够则移动数据 2、不够则直接扩容
    void ModifyRemainSpace(size_t len){
        if (TailRemainSpace() >= len) return;
        if (HeadRemainSpace() + TailRemainSpace() >= len) {
            int datasize = DataLength();
            std::copy(ReadAddress(), WriteAddress(), Begin());
            _read_pos = 0;
            _write_pos = datasize;
        } else {
            // 扩容
            int new_capacity = _capacity + len;
            assert(new_capacity < MAX_CAPACITY);
            _buffer.resize(new_capacity);
            _capacity = new_capacity;
        }
    }

    // 向缓冲区写入定长数据
    // 1、以指针的形式
    void WriteAsStr(const char* sptr, size_t len){
        if (len == 0) return;
        ModifyRemainSpace(len); // 先做判断
        std::copy(sptr, sptr + len, WriteAddress());
    }
    void WriteAsStrAndPush(const char* sptr, size_t len){
        WriteAsStr(sptr, len);
        ModifyWriteOffset(len);
    }

    // 2、以string的形式
    void WriteAsString(const std::string& str){
        WriteAsStr(str.c_str(), str.size());
    }
    void WriteAsStringAndPush(const std::string& str){
        WriteAsString(str);
        ModifyWriteOffset(str.size());
    }

    // 3、以Buffer的形式
    void WriteAsBuffer(Buffer& buffer){
        WriteAsStr(buffer.ReadAddress(), buffer.DataLength());
    }
    void WriteAsBufferAndPush(Buffer& buffer){
        WriteAsBuffer(buffer);
        ModifyWriteOffset(buffer.DataLength());
    }

    // 从缓冲区中读取定长数据
    // 1、以指针的形式
    size_t ReadAsStr(char* sptr, size_t len){
        int available_data = DataLength();
        if (available_data < len) len = available_data; // 先做判断
        std::copy(ReadAddress(), ReadAddress() + len, sptr);
        return len;
    }
    size_t ReadAsStrAndPop(char* sptr, size_t len){
        int ret = ReadAsStr(sptr, len);
        ModifyReadOffset(ret);
        return ret;
    }

    // 2、以string的形式
    size_t ReadAsString(std::string& str, size_t len){
        int available_data = DataLength();
        // 如果期望读取的数据大于当前数据总数，直接返回当前缓冲区中的所有数据
        if (available_data < len) len = available_data; // 先做判断
        str.resize(len);
        return ReadAsStr(&str[0], len);
    }
    size_t ReadAsStringAndPop(std::string& str, size_t len){
        int ret = ReadAsString(str, len);
        ModifyReadOffset(ret);
        return ret;
    }

    // 3、以Buffer的形式
    size_t ReadAsBuffer(Buffer& buffer, size_t len){
        if (buffer._capacity < len) buffer.Resize(len);
        int ret = ReadAsStr(buffer.ReadAddress(), len);
        buffer.ModifyWriteOffset(ret); // write指针要随着写入数据的增多而移动
        return ret;
    }
    size_t ReadAsBufferAndPop(Buffer& buffer, size_t len){
        int ret = ReadAsBuffer(buffer, len);
        ModifyReadOffset(ret);
        return ret;
    }

    /*memchr 函数的主要作用是在一个指定长度的内存区域中查找一个特定的字节值。 void *memchr(const void *s, int c, size_t n);*/
    char* FindLineEnd(){
        char* ret = (char*)memchr(ReadAddress(), '\n', DataLength());
        return ret;
    }

    // 按行读取缓冲区中的内容
    std::string GetLine(){
        std::string temp;
        char* ret = nullptr;
        if ((ret = FindLineEnd()) == nullptr) return temp;
        ReadAsString(temp, ret - ReadAddress() + 1);
        return temp;
    }
    std::string GetLineAndPop(){
        std::string temp = GetLine();
        if (!temp.empty()) {
            ModifyReadOffset(temp.size());
        }
        return temp;
    }

    //清空缓冲区
    void Clear() {
        //将偏移量归0即可，后续覆盖写入
        _write_pos = 0;
        _read_pos = 0;
    }
    void Print(){
        char* begin = ReadAddress();
        while(begin != WriteAddress()){
            printf("%c", *begin);
            begin++;
        }
        printf("\n");
    }
};
// 勘误记录
// date 2025.1.10
// 在Buffer a;与Buffer b;之间的读取与写入中，例如要从a中读取len个数据放入b中时，在函数设计时要注意b的write指针要随着写入数据的增多而移动

int main()
{
    Buffer b;
    std::string s = "hello1\nhello2\n";
    b.WriteAsStringAndPush(s);
    std::cout << b.DataLength() << std::endl;

    Buffer a = b;
    a.WriteAsBufferAndPush(b);
    std::cout << a.DataLength() << std::endl;

    Buffer c;
    a.ReadAsBuffer(c, 5);
    std::cout << c.ReadAddress() << std::endl;
    c.Print();

    Buffer d;
    for(int i = 0; i < 300; i++)
    {
        std::string temp = "hello modou" + std::to_string(i) + '\n';
        d.WriteAsStringAndPush(temp);
    }

    while(1)
    {
        std::string ret = d.GetLineAndPop();
        if(ret.size() == 0) break;
        std::cout << ret << std::endl;
    }

    // std::string temp;
    // //b.ReadAsStringAndPop(temp, 5);
    // temp = b.GetLineAndPop();
    // std::cout << temp << std::endl;
    // std::cout << b.DataLength() << std::endl;
    // temp = b.GetLineAndPop();
    // std::cout << temp << std::endl;
    // std::cout << b.DataLength() << std::endl;

    return 0;
}

